/**
 * 递归遍历一个对象（或数组），以便收集其所有“深层”依赖项。
 * 这在Vue的响应式系统中非常有用，以确保当依赖项的值变化时，相关的视图可以正确地更新
 */
import { _Set as Set, isObject, isArray } from '../util/index'
import type { SimpleSet } from '../util/index' // 导入SimpleSet类型，用于类型检查
import VNode from '../vdom/vnode' // 从虚拟DOM模块导入VNode类
import { isRef } from '../../v3' // 从v3模块导入isRef函数，用于检查值是否为响应式引用
// 创建一个新的Set实例，用于存储已经遍历过的依赖对象
const seenObjects = new Set()

/**
 * Recursively traverse an object to evoke all converted
 * getters, so that every nested property inside the object
 * is collected as a "deep" dependency.
 */
/**
 * 递归遍历一个对象，以触发所有转换后的getter，
 * 从而使对象内的每个嵌套属性都被收集为“深度”依赖。
 */
export function traverse(val: any) {
  _traverse(val, seenObjects) // 调用内部_traverse函数进行递归遍历
  seenObjects.clear() // 清空seenObjects集合，为下一次遍历做准备
  return val // 返回原始值
}

function _traverse(val: any, seen: SimpleSet) {
  let i, keys // 声明变量i和keys，用于后续遍历
  const isA = isArray(val) // 检查val是否为数组

  // 如果val不是对象或数组，或者设置了__v_skip标志，或者已被冻结，或者是VNode实例，则直接返回
  if (
    (!isA && !isObject(val)) ||
    val.__v_skip /* ReactiveFlags.SKIP */ ||
    Object.isFrozen(val) ||
    val instanceof VNode
  ) {
    return
  }
  // 如果val是响应式对象（即具有__ob__属性），则检查其依赖ID是否已在seen集合中
  if (val.__ob__) {
    const depId = val.__ob__.dep.id
    if (seen.has(depId)) { // 如果已存在，则直接返回，避免重复遍历
      return
    }
    seen.add(depId)  // 否则，将其添加到seen集合中
  }
  if (isA) { // 如果val是数组，则遍历数组的每个元素
    i = val.length
    // 从数组末尾开始遍历，确保不会因修改数组长度而导致问题
    while (i--) _traverse(val[i], seen)
    // 如果val是响应式引用，则递归遍历其值
  } else if (isRef(val)) {
    _traverse(val.value, seen)
  } else {
    // 如果val是普通对象，则遍历其所有属性
    keys = Object.keys(val)
    i = keys.length
    // 从属性末尾开始遍历
    while (i--) _traverse(val[keys[i]], seen)
  }
}
